package eu.ec.ellipcis.integration.ws.config;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.jms.ConnectionFactory;
import javax.jms.Queue;
import javax.naming.Context;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.support.destination.DestinationResolver;
import org.springframework.jms.support.destination.JndiDestinationResolver;
import org.springframework.jndi.JndiObjectFactoryBean;
import org.springframework.jndi.JndiTemplate;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.server.endpoint.MessageEndpoint;
import org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter;
import org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.MethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.MethodReturnValueHandler;
import org.springframework.ws.server.endpoint.mapping.UriEndpointMapping;
import org.springframework.ws.soap.server.endpoint.SoapFaultAnnotationExceptionResolver;

import eu.ec.ellipcis.integration.ws.client.domain.AccountBalanceRequest;
import eu.ec.ellipcis.integration.ws.client.domain.AccountBalanceResponse;
import eu.ec.ellipcis.integration.ws.policy.CustomValidationPolicy;
import eu.ec.ellipcis.integration.ws.policy.TicketCustomValidationPolicy;
import eu.ec.ellipcis.integration.ws.policy.TicketXmlValidationPolicy;
import eu.ec.ellipcis.integration.ws.policy.XmlValidationPolicy;

@Configuration
public class WebServiceConfiguration {

    /* ---- Constants ---- */
    Log log = LogFactory.getLog(this.getClass());


    /* ---- Instance Variables ---- */

//    @Value("#{wsInboundGateway}")
//    private MessageEndpoint wsInboundGateway = null;

    @Value("#{jmsConnectionFactory}")
    private ConnectionFactory connectionFactory = null;

    @Value("#{jmsMessageQueue}")
    private Queue messageQueue = null;

//    @Autowired
//    private TicketXmlValidationPolicy ticketXmlValidationPolicy = null;
//    @Autowired
//    private TicketCustomValidationPolicy ticketCustomValidationPolicy = null;

    /* ---- Constructors ---- */
    public WebServiceConfiguration() {
        super();
        log.info("WebServiceConfiguration - etrustex-integration-ws");
    }

    /* ---- Configuration Beans ---- */

    @Bean
    public Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        //marshaller.setClassesToBeBound(AccountBalanceRequest.class, AccountBalanceResponse.class);
        marshaller.setContextPath("eu.ec.ellipcis.integration.ws.domain.jaxb");
        return marshaller;
    }

//    @Bean
//    public QueueChannel messageChannel() {
//        return new QueueChannel();
//    }

//
//    @Bean
//    public MarshallingPayloadMethodProcessor marshallingPayloadMethodProcessor() {
//        MarshallingPayloadMethodProcessor processor = new MarshallingPayloadMethodProcessor();
//        processor.setMarshaller(jaxb2Marshaller());
//        return processor;
//    }
//
//    @Bean
//    public DefaultMethodEndpointAdapter defaultMethodEndpointAdapter() {
//        DefaultMethodEndpointAdapter endpointAdapter = new DefaultMethodEndpointAdapter();
//        List<MethodArgumentResolver> methodArgumentResolvers = new ArrayList<MethodArgumentResolver>();
//        methodArgumentResolvers.add(marshallingPayloadMethodProcessor());
//        List<MethodReturnValueHandler> methodReturnValueHandlers = new ArrayList<MethodReturnValueHandler>();
//        methodReturnValueHandlers.add(marshallingPayloadMethodProcessor());
//        endpointAdapter.setMethodArgumentResolvers(methodArgumentResolvers);
//        endpointAdapter.setMethodReturnValueHandlers(methodReturnValueHandlers);
//        return endpointAdapter;
//    }
//
//    @Bean
//    public SoapFaultAnnotationExceptionResolver soapFaultAnnotationExceptionResolver() {
//        SoapFaultAnnotationExceptionResolver exceptionResolver = new SoapFaultAnnotationExceptionResolver();
//        return exceptionResolver;
//    }
//
//    @Bean (name = "xmlValidationPolicyMap")
//    public Map<String, XmlValidationPolicy> xmlValidationPolicyMap() {
//        Map<String, XmlValidationPolicy> xmlValidationPolicies = new HashMap<String, XmlValidationPolicy>();
//        xmlValidationPolicies.put("ticketRequest", ticketXmlValidationPolicy);
//        return xmlValidationPolicies;
//    }
//
//    @Bean (name = "customValidationPolicyMap")
//    public Map<String, CustomValidationPolicy> customValidationPolicyMap() {
//        Map<String, CustomValidationPolicy> customValidationPolicies = new HashMap<String, CustomValidationPolicy>();
//        customValidationPolicies.put("ticketRequest", ticketCustomValidationPolicy);
//        return customValidationPolicies;
//    }
//
//    @Bean
//    public UriEndpointMapping uriEndpointMapping() {
//        UriEndpointMapping uriEndpointMapping = new UriEndpointMapping();
//        uriEndpointMapping.setDefaultEndpoint(wsInboundGateway);
//        return uriEndpointMapping;
//    }

    /* ---- JMS Setup - START ---- */

    @Bean
    public JndiTemplate jndiTemplate() {
        Properties environment = new Properties();
        environment.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
        environment.put(Context.PROVIDER_URL, "t3://localhost:7001");
        JndiTemplate jndiTemplate = new JndiTemplate(environment);
        return jndiTemplate;
    }

    /**
     * See also the instance variable definition for a {@link ConnectionFactory}.
     */
    @Bean
    public JndiObjectFactoryBean jmsConnectionFactory() {
        JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
        jndiObjectFactoryBean.setJndiTemplate(jndiTemplate());
        jndiObjectFactoryBean.setJndiName("jms/MessageQueueConnectionFactory");
        return jndiObjectFactoryBean;
    }

    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
        cachingConnectionFactory.setTargetConnectionFactory(connectionFactory);
        cachingConnectionFactory.setSessionCacheSize(10);
        return cachingConnectionFactory;
    }

    @Bean
    public DestinationResolver destinationResolver() {
        JndiDestinationResolver destinationResolver = new JndiDestinationResolver();
        destinationResolver.setJndiTemplate(jndiTemplate());
        destinationResolver.setCache(Boolean.TRUE);
        return destinationResolver;
    }

    @Bean
    public JmsTemplate jmsTemplate() {
        JmsTemplate jmsTemplate = new JmsTemplate();
        jmsTemplate.setConnectionFactory(connectionFactory());
        jmsTemplate.setDestinationResolver(destinationResolver());
        return jmsTemplate;
    }

    @Bean
    public JndiObjectFactoryBean jmsMessageQueue() {
        JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
        jndiObjectFactoryBean.setJndiTemplate(jndiTemplate());
        jndiObjectFactoryBean.setJndiName("jms/MessageQueue");
        return jndiObjectFactoryBean;
    }

    @Bean
    public Queue messageQueue() {
        return messageQueue;
    }

    /* ---- JMS Setup - END ---- */


}
